/* 
    当无法确定对象中有哪些属性时（或者说对象中会出现任意多属性时），需要用到索引签名类型
    1. 使用 [key:string] 来约束允许出现的属性类型，即 key 的类型
    2. key 只是一个占位符，可以换成任意合法名称
    3. 隐藏知识点： js 中对象 {} 的键都是 string 类型
 */
type AnyObj<Type> = {
    [key: string]: Type
}

const anyObj1: AnyObj<number> = {
    "a": 1,
    "b": 2
}
/* ********************************************映射类型******************************************** */
/* 
    映射类型：基于旧类型创建新类型（对象类型），减少重复，提升开发效率
        1. 映射类型是基于索引签名类型的，所以该语法类似于索引签名类型，也用了 []
        2. Key in PrpoKeys 表示 Key 可以是 PropKeys 联合类型中的任意一个，类似于 forin(let k in obj)
        3. 注意：映射类型只能在类型别名中使用，不能在接口中使用。

    映射类型：除了根据联合类型创建新类型外，还可以根据对象创建类型
        1. [key in keyof type4]
        2. 先执行 keyof type4 获取到对象类型type4 中苏邮件的联合类型，"a"|"b"|"c"
        2. 再执行 key in ... 就表示key可以使type4中所有键名称的任意一个
*/
type type1 = "x" | "y" | "z";
type type2 = {
    "x": number,
    "y": number,
    "z": number
}
type type3 = { [key in type1]: number };

// type1 是一种类型，type2 和 type3 等价，是一种新类型
const tt1: type1 = "x";
const tt2: type2 = {
    x: 0,
    y: 0,
    z: 0
}
const tt3: type3 = {
    x: 0,
    y: 0,
    z: 0
}
// 映射类型只能在类型别名中使用，不能在接口中使用。
interface testInterface{
    [key in type1]:number
}

// 映射类型根据对象创建类型
type type4 = {
    a:number,
    b:string,
    c:boolean
}
// type5 改变了键的类型
type type5  = {[key in keyof type4]:number}